#include "Path.h"

#include "math.h"
#include <limits>

using namespace std;

//
//  empty constructor
//
Path::Path( ) 
{ 
   p_init = false; 
   p_unique_id = 0;
} 

//~Path() { };

//
//  copy constructor
// 
Path::Path( const Path& p )
{
   p_slices = p.p_slices;
   p_labels = p.p_labels;
   p_costs = p.p_costs;
   p_accumulated_costs = p.p_accumulated_costs;
   p_x = p.p_x;
   p_y = p.p_y;
   p_unique_id = p.p_unique_id;
   p_vtk_filenames = p.p_vtk_filenames;
}

Path::Path( const Path* p )
{
   p_slices = p->p_slices;
   p_labels = p->p_labels;
   p_costs = p->p_costs;
   p_accumulated_costs = p->p_accumulated_costs;
   p_x = p->p_x;
   p_y = p->p_y;
   p_unique_id = p->p_unique_id;
   p_vtk_filenames = p->p_vtk_filenames;
}

//
//  operator=
//
Path& Path::operator=( const Path& p )
{
   p_slices = p.p_slices;
   p_labels = p.p_labels;
   p_costs = p.p_costs;
   p_accumulated_costs = p.p_accumulated_costs;
   p_x = p.p_x;
   p_y = p.p_y;
   p_unique_id = p.p_unique_id;
   p_vtk_filenames = p.p_vtk_filenames;

   return *this;
}

//
// clear - reset the path
//
void Path::clear()
{
   p_slices.clear();
   p_labels.clear();
   p_costs.clear();
   p_accumulated_costs.clear();
   p_x.clear();
   p_y.clear();
   p_final_cost = 0;
   p_init = false;

   using namespace std;
   p_unique_id = 0;
   p_vtk_filenames.clear();
}

bool Path::overlap( const Path* P )
{
   bool overlap = false;

   // check for overlapping slices
   for( unsigned int i = 0; i < p_slices.size(); i++ )
   {
      for( unsigned int j = 0; j < P->p_slices.size(); j++ )
      {
         if( p_slices[ i ] == P->p_slices[ j ] )
         {
            // are the x and ys the same?
            if( ( p_x[ i ] == P->p_x[ j ] ) &&
                ( p_y[ i ] == P->p_y[ j ] ) )
            {
               cout << "overlap at slice " << p_slices[ i ] << " and (" 
                    << p_x[ i ] << ", " << p_y[ i ] << ")" << endl;
               overlap = true;
            }
         }
      }
   }

   return overlap;

}

//
//  compares paths that DO NOT OVERLAP to see if they are close enough to
//  merge
//
float Path::combine( const Path* P )
{
   float d = numeric_limits< float >::max();
   // check for overlapping slices
   for( unsigned int i = 0; i < p_slices.size(); i++ )
   {
      for( unsigned int j = 0; j < P->p_slices.size(); j++ )
      {
         if( P->p_slices[ P->p_slices.size()-1 ] < p_slices[ p_slices.size() - 1 ] )
         {
            if( p_slices[ i ] - 1 == P->p_slices[ j ] )
            {
               // are the x and ys close to eachother?
               float d = sqrt( powf( p_x[ i ] - P->p_x[ j ], 2 ) +
                               powf( p_y[ i ] - P->p_y[ j ], 2 ) );
               return d;
            }
         }
         
         else if( P->p_slices[ P->p_slices.size()- 1 ] > p_slices[ p_slices.size() - 1 ] )
         {
            if( p_slices[ i ] + 1 == P->p_slices[ j ] )
            {
               // are the x and ys close to eachother?
               float d = sqrt( powf( p_x[ i ] - P->p_x[ j ], 2 ) +
                               powf( p_y[ i ] - P->p_y[ j ], 2 ) );
               return d;
            }
         }
      }
   }

   return d;

}
/*
vector< int > Path::getNearestSlices( const Path* path1, const Path* path2 )
{
   // get min and max slices for path1
   int p1_min, p1_max;
   path1->getMinMaxSlice( p1_min, p1_max );

   // get min and max slices for path2
   int p2_min, p2_max;
   path2->getMinMaxSlice( p2_min, p2_max );

   vector< int > ns(2);
  
   if( p1_max < p2_min ) // p1 is above p2
   {
      ns[ 0 ] = p1_max;
      ns[ 1 ] = p2_min;
   }
   else if( p2_max < p1_min ) // p2 is above p2
   {
      ns[ 0 ] = p1_min;
      ns[ 1 ] = p2_max;
   }

   return ns;
}
*/


//
//  merge paths that are sequential slices
//
void Path::merge( const Path& P )
{
   cout << "\nbefore: " << endl;
   cout << "this: " << endl ;
   print();
   cout << "P: " << endl ;
   P.print();

   //
   // *this path is above P  (in decreasing order)
   //  
   if( P.p_slices[ P.p_slices.size()-1 ] < p_slices[ p_slices.size() - 1 ] )
   {
      cout << "slices in new P < slices in *this" << endl ;
      for( unsigned int i = 0 ; i < P.p_slices.size(); i++ )
      {
         // skip overlapping slices
         if( p_slices[ p_slices.size() - 1 ] != P.p_slices[i] )
         {
            //
            // concatonate everything
            //
            p_slices.push_back( P.p_slices[i] );
            p_labels.push_back( P.p_labels[i] );
            p_costs.push_back( P.p_costs[i] );
            p_accumulated_costs.push_back( P.p_accumulated_costs[i] );
            p_x.push_back( P.p_x[i] );
            p_y.push_back( P.p_y[i] );
            //p_unique_id = ? TODO
            // filename doesnt change
            //for( unsigned int k = 0; k < P.p_vtk_filenames.size(); k++ )
            //   p_vtk_filenames.push_back( P.p_vtk_filenames[ k ] );
         }

      }
   }
   //
   // *this is below P (in decreasing order) 
   //
   else if( P.p_slices[ P.p_slices.size()- 1 ] > 
            p_slices[ p_slices.size() - 1 ] )
   {
      cout << "slices in new P > slices in *this" << endl ;
      for( int i = P.p_slices.size() - 1; i >= 0; i-- )
      {
         //cout << "i: " << i << endl ;
         //cout << P.p_slices[ i ] << endl;
         if( P.p_slices[ i ] != p_slices[ 0 ] )
         {
            p_slices.insert( p_slices.begin(), P.p_slices[i] );
            p_labels.insert( p_labels.begin(), P.p_labels[i] );
            p_costs.insert( p_costs.begin(), P.p_costs[i] );
            p_accumulated_costs.insert( p_accumulated_costs.begin(), 
                  P.p_accumulated_costs[i] );
            p_x.insert( p_x.begin(), P.p_x[i] );
            p_y.insert( p_y.begin(), P.p_y[i] );
            //p_unique_id = ? TODO
            // filename doesnt change
            //for( unsigned int k = 0; k < P.p_vtk_filenames.size(); k++ )
            //   p_vtk_filenames.push_back( P.p_vtk_filenames[ k ] );
         }
      }
   }
   else
   {
      cout << "error, need to, but can't merge paths" << endl ;
   }

   /*
   else // p.beginningSlice() == lastSlice 
   {
   cout << "beginningSlice == lastSilce. what do I do?" << endl ;

   // skip the first label in P
   for( unsigned int i = 1 ; i < P.p_slices.size(); i++ )
   {
   p_slices.insert( p_slices.begin()+i, P.p_slices[i] );
   p_labels.insert( p_labels.begin()+i, P.p_labels[i] );
   p_costs.insert( p_costs.begin()+i, P.p_costs[i] );
   p_accumulated_costs.insert( p_accumulated_costs.begin()+i, 
   P.p_accumulated_costs[i] );
   }

   }
    */
   cout << "after" << endl;
   print();
}

//
//  merge paths that share a last and first slice
//
void Path::merge( const Path& P, bool use_this )
{
   cout << "merging same slices!" << endl ;
   cout << "\nbefore: " << endl;
   print();
   P.print();

   if( use_this ) // keep the last label in *this* path and
   {               // skip the first label in P
      for( unsigned int i = 1 ; i < P.p_slices.size(); i++ )
      {
         p_slices.push_back( P.p_slices[i] );
         p_labels.push_back( P.p_labels[i] );
         p_costs.push_back( P.p_costs[i] );
         p_accumulated_costs.push_back( P.p_accumulated_costs[i] );
         p_x.push_back( P.p_x[i] );
         p_y.push_back( P.p_y[i] );
         //p_unique_id = ? TODO
         for( unsigned int k = 0; k < P.p_vtk_filenames.size(); k++ )
            p_vtk_filenames.push_back( P.p_vtk_filenames[ k ] );
      }
   }
   else // delete the last label in *this* path and add onto it
   {     // with P
      p_slices.pop_back();
      p_labels.pop_back();
      p_costs.pop_back();
      p_accumulated_costs.pop_back();
      for( unsigned int i = 0 ; i < P.p_slices.size(); i++ )
      {
         p_slices.push_back( P.p_slices[i] );
         p_labels.push_back( P.p_labels[i] );
         p_costs.push_back( P.p_costs[i] );
         p_accumulated_costs.push_back( P.p_accumulated_costs[i] );
         p_x.push_back( P.p_x[i] );
         p_y.push_back( P.p_y[i] );
         //p_unique_id = ? TODO
         for( unsigned int k = 0; k < P.p_vtk_filenames.size(); k++ )
            p_vtk_filenames.push_back( P.p_vtk_filenames[ k ] );
      }
   }

   cout << "after" << endl;
   print();
}

//
//  return the first label in the path
//
long int Path::getFirstLabel()
{
   return *(p_labels.begin());
}

//
//  return the first slice in the path
//
int Path::beginningSlice() const
{
   return p_slices[0];
}

//
//  return the last slice in the path
//
int Path::lastSlice() const
{
   return p_slices[ p_slices.size()-1 ];
}

//
//  returns the first slice in the path
//
int Path::firstSlice() const
{
   return p_slices[ 0 ];
}

//
//  get a list of all the slices
//
vector< int >& Path::getSlices() { return p_slices; }

//
//  getCost
//
float Path::getCost() const { return p_final_cost; } 

//
//  setCost
//
void Path::setCost( float cost ) { p_final_cost = cost ; } 

//
//  getSlice at index i
//
int Path::getSlice( int i ) const
{
   return p_slices[ i ];
}

//
//  getLabel at index i
//
long int Path::getLabel( int i ) const
{
   return p_labels[ i ];
}

//
//  getLabel by slice 
//
long int Path::getLabelBySlice( int i ) const
{
   for( unsigned int s = 0; s < p_slices.size(); s++ )
   {
      if( p_slices[ s ] == i )
         return p_labels[ s ];
   }

   return -1; // not found
}

//
//  get the accumulative cost at index i
//
float Path::getAccCost( int i ) const 
{ 
   return p_accumulated_costs[i]; 
} 

//
//  get the cost at index i
//
float Path::getCost( int i ) const 
{ 
   return p_costs[i]; 
} 

//
//  sliceExits - is slice s in the path?
//
bool Path::sliceExists( int s )
{
   vector< int >::const_iterator iter = 
      find( p_slices.begin(), p_slices.end(), s );
   if( iter != p_slices.end() )
      return true;

   return false;
}

vector< int >& Path::getXs() { return p_x; } 
vector< int >& Path::getYs() { return p_y; } 

//
//  get X for slice i
//
int Path::getX( int i ) const
{
   int x = -1;
   //for( unsigned int b = 0; b < p_slices.size(); b++ )
   //   cout << p_slices[b] << " ";
   //cout << endl ;
   // get the index of this slice
   vector< int >::const_iterator iter = 
      find( p_slices.begin(), p_slices.end(), i );
   if ( iter != p_slices.end() )
   {
      int ni = p_slices.size() - distance( iter, p_slices.end() );
      //cout << "ni,i: " << ni << "," << i << endl ;
      x = p_x[ni];
   }

   return x;
} 

//
//  get Y for slice i
//
int Path::getY( int i ) const
{
   int y = -1;
   // get the index of this slice
   vector< int >::const_iterator iter = 
      find( p_slices.begin(), p_slices.end(), i );
   if( iter != p_slices.end() )
   {
      int ni = p_slices.size() - distance( iter, p_slices.end() );
      y = p_y[ni];
   }
   return y;
} 

//
//  return the label for index i
//
long int Path::getIndex( int i )
{
   return p_labels[ i ];
}

//
//  getLastLabel
//
long int Path::getLastLabel() const
{
   return p_labels[ p_labels.size() - 1 ];
}

//
//  getFirstLabel
//
long int Path::getfirstLabel() const
{
   return p_labels[ 0 ];
}

//
// set the VTK filename
//
void Path::setVTKFilename( string vtk_filename )
{
   p_vtk_filenames.insert( p_vtk_filenames.begin(), vtk_filename );
}

//
// get the vkt filenames (should just be one filename)
//
vector< string > Path::getVTKFilenames()
{
   return p_vtk_filenames;
}

//
//  id for this path
//
unsigned int Path::getID() { return p_unique_id; }

// 
// set the id for this path
//
void Path::setID( unsigned int id ) { p_unique_id = id ; } 

//
//  initialize
//
bool Path::init() const { return p_init; } 

//
//  size of path
//
unsigned int Path::size() const { return p_slices.size() ; }

//
//  number of sections the path spans
//
unsigned int Path::length() const { 

   int min, max;
   getMinMaxSlice( min, max );
   return max - min ; 
}


//
// initPath - start a path
//
void Path::initPath( int slice, long int label, 
      float cost, float acc_cost, 
      int x, int y )
{
   p_slices.push_back( slice );
   p_labels.push_back( label );
   p_costs.push_back( cost );
   p_accumulated_costs.push_back( acc_cost );
   p_x.push_back( x );
   p_y.push_back( y );

   p_final_cost = acc_cost;

   p_init = true;

   //p_path[ slice ] = label;
}

//
//  add to the path at the beginning of the path
//
void Path::add( int slice, long int label, float cost, float acc_cost,
      int x, int y )
{
   p_slices.insert( p_slices.begin(), slice );
   p_labels.insert( p_labels.begin(), label );
   p_costs.insert( p_costs.begin(), cost );
   p_accumulated_costs.insert( p_accumulated_costs.begin(), acc_cost );
   p_x.insert( p_x.begin(), x );
   p_y.insert( p_y.begin(), y );

   //p_path[ slice ] = label;
}

//
//  add to the path at the end of the path
//
void Path::addEnd( int slice, long int label, float cost, float acc_cost,
      int x, int y )
{
   p_slices.insert( p_slices.end(), slice );
   p_labels.insert( p_labels.end(), label );
   p_costs.insert( p_costs.end(), cost );
   p_accumulated_costs.insert( p_accumulated_costs.end(), acc_cost );
   p_x.insert( p_x.end(), x );
   p_y.insert( p_y.end(), y );

   p_final_cost = acc_cost;

   //p_path[ slice ] = label;
}

//
//  returns the label for the i'th slice in this path
//
long int Path::get( int i )
{
   //
   // does a label exist for this slice (maybe we skipped it!)
   //
   vector< int >::iterator loc = 
      std::find( p_slices.begin(), p_slices.end(), i );

   if( loc != p_slices.end() )
   {
      //
      //  if we do have a label for this slice, what is its index
      //  in the label list?
      //
      int loc_index = distance( p_slices.begin(), loc );
      //cout << "found " << *loc << " at index " << loc_index 
      //   << ", with label " << p_labels[loc_index] << endl ;
      return p_labels[loc_index];
   }

   return 0;

}

//
// getMinMaxSlice
//
void Path::getMinMaxSlice( int& min, int& max ) const
{
   vector< int >::const_iterator min_loc = min_element( p_slices.begin(), p_slices.end() );
   vector< int >::const_iterator max_loc = max_element( p_slices.begin(), p_slices.end() );
   min = *min_loc;
   max = *max_loc;
}

//
//  print to stdout
//
void Path::print() const
{
   //for( map< int, long int >::const_iterator iter = p_path.begin();
   //     iter != p_path.end(); ++iter )
   //   cout << iter->first << ": " << iter->second << "  ";
   //cout << endl ;
   cout << " (slice, label, cost, acc_cost, x, y)\n";
   for( unsigned int i = 0 ; i < p_slices.size(); ++i )
   {
      cout << p_slices[i] << " " ;
      cout << p_labels[i] << " " ;
      cout << p_costs[i] << " " ;
      cout << p_accumulated_costs[i] << " ";
      cout << p_x[i] << " ";
      cout << p_y[i] << " - ";
      cout << "\n" ;
      //cout << "\t" ;
   }
   cout << p_unique_id << " ";
   for( unsigned int j = 0; j < p_vtk_filenames.size(); j++ )
      cout << p_vtk_filenames[j] << " ";
   cout << endl;

}

//
//  write to an xml structure 
//
void Path::writeXMLPath( TiXmlElement* pt )
{
   for( unsigned int i = 0; i < p_slices.size(); i++ )
   {
      TiXmlElement * sliceElement;
      sliceElement = new TiXmlElement( "SliceElement" );  

      pt->LinkEndChild( sliceElement );

      sliceElement->SetAttribute( "slice", p_slices[i] );
      sliceElement->SetAttribute( "label", p_labels[i] );
      sliceElement->SetDoubleAttribute( "cost", p_costs[i] );
      sliceElement->SetDoubleAttribute( "accumCost", p_accumulated_costs[i] );
      sliceElement->SetAttribute( "x", p_x[i] );
      sliceElement->SetAttribute( "y", p_y[i] );
      //sliceElement->SetAttribute("x", 250);
      //sliceElement->SetAttribute("y", 250);
   }
}

//
// read an xml structure
//
void Path::readXMLPath( TiXmlElement* pathNode )
{
   int slice = -1, label = -1, x = -1, y = -1;
   double cost = -1, accCost = -1 ;
   TiXmlElement* sliceElement = pathNode->FirstChildElement();
   for( ; sliceElement; sliceElement = sliceElement->NextSiblingElement() )
   {
      //readXMLPath( pathNode );
      sliceElement->QueryIntAttribute( "slice", &slice );
      sliceElement->QueryIntAttribute( "label", &label );
      sliceElement->QueryDoubleAttribute( "cost", &cost );
      sliceElement->QueryDoubleAttribute( "accumCost", &accCost );
      sliceElement->QueryIntAttribute( "x", &x );
      sliceElement->QueryIntAttribute( "y", &y );

      if( !p_init )
         initPath( slice, label, cost, accCost, x, y );
      else
         addEnd( slice, label, cost, accCost, x, y );

   }
   //print();
}

//
// write to a file (not supported)
//
void Path::print(ofstream& out) const
{
   //for( map< int, long int >::const_iterator iter = p_path.begin();
   //     iter != p_path.end(); ++iter )
   //   out << iter->first << "  " << iter->second << "\t";
   //out << endl ;
   for( unsigned int i = 0 ; i < p_slices.size(); ++i )
   {
      out << p_slices[i] << " " ;
      out << p_labels[i] << " " ;
      out << p_costs[i] << " " ;
      out << p_accumulated_costs[i] << " ";
      out << p_x[i] << " ";
      out << p_y[i] << " - ";
      cout << "\t" ;
   }
   cout << p_unique_id << " ";
   for( unsigned int j = 0; j < p_vtk_filenames.size(); j++ )
      cout << p_vtk_filenames[j] << " ";
   out << endl;

}

//
//
//  List of Paths
//
//

ListOfPaths::ListOfPaths() { } 

ListOfPaths::ListOfPaths( string path_filename ) 
{
   readPaths( path_filename );
} 

ListOfPaths::ListOfPaths( const ListOfPaths& lop )
{
   p_paths = lop.p_paths;
}

ListOfPaths& ListOfPaths::operator=( const ListOfPaths& P )
{
   p_paths = P.p_paths;
   return *this;
}

void ListOfPaths::remove( int index )
{
   p_paths.erase( p_paths.begin() + index );
}

void ListOfPaths::deletePaths( vector< int > ids )
{
   vector< Path >::iterator pathIter;
   pathIter = p_paths.begin();
   while( pathIter != p_paths.end() )
   {
      int pid = pathIter->getID();
      if( find( ids.begin(), ids.end(), pid ) != ids.end() )
      {
         pathIter = p_paths.erase( pathIter );
      }
      else
         ++pathIter;

   }
}

unsigned int ListOfPaths::size() const { return p_paths.size(); }

Path ListOfPaths::get( int i ) const { return p_paths[ i ]; }

Path& ListOfPaths::getRef( int i ) { return p_paths[ i ]; }

Path* ListOfPaths::getPathByIndex( unsigned int i ) 
{ 
   return &(p_paths[ i ]); 
}

Path* ListOfPaths::getPathById( unsigned int id ) 
{
   for( unsigned int i = 0; i < p_paths.size(); i++ )
   {
      if( p_paths[i].getID() == id )
         return &(p_paths[i]);
   }

   cout << "ERROR: No path found for id " << id << endl;
   return &(p_paths[0]); // todo - fix THIS@!!!
}

void ListOfPaths::addPath( float c, Path P )
{
   p_paths.push_back( P );
}

void ListOfPaths::addPath( Path P )
{
   p_paths.push_back( P );
}

void ListOfPaths::addPaths( ListOfPaths* lop )
{
   for( unsigned int p = 0; p < lop->size(); p++ )
      addPath( lop->getPathByIndex( p ) );
}

Path ListOfPaths::getMaxPath()
{
   int max_path_index = -1;
   float max_path_cost = (float)INT_MIN;
   for( unsigned int p = 0; p < p_paths.size(); p++ )
   {
      if( max_path_cost < p_paths[p].getCost() )
      {
         max_path_cost = p_paths[p].getCost();
         max_path_index = p;
      }
   }

   if( max_path_index == -1 )
   {
      cout << "ERROR: max_path_index not found" << endl;
      exit(1);
   }

   //cout << "blah: "; p_paths[max_path_index].print();

   return p_paths[ max_path_index ];
}


void ListOfPaths::readPaths( string filename )
{
   ifstream fp_in;
   fp_in.open( filename.c_str() ); 

   // read in the first line, which is a comment
   string junk;
   getline( fp_in, junk );

   while( true )
   {
      string path_string;
      getline( fp_in, path_string );

      if( fp_in.eof() ) break ;

      stringstream sstr( path_string );
      //cout << "path: " << path_string << endl;

      Path path;
      while( true )
      {

         int slice;
         sstr >> slice;
         //cout << "slice: " << slice ;

         if( sstr.fail() ) break;
         //if( sstr.eof() ) break;

         long int label;
         sstr >> label;
         //cout << "  label: " << label ;

         // ignore the next two fields, but read them in anyway
         float cost1, cost2;
         sstr >> cost1;
         //cout << " " << cost ;
         sstr >> cost2;
         //cout << " " << cost ;

         if( !path.init() )
            path.initPath( slice, label, cost1, cost2, 0, 0 );
         else
            path.addEnd( slice, label, cost1, cost2, 0, 0 );

         //cout << endl ;


      }

      p_paths.push_back( path );
   }

   // did it work?
   //for( unsigned i = 0; i < p_paths.size(); i++)
   //{
   //   p_paths[i].print(); 
   //}
}

void ListOfPaths::resetIDs( bool setFilename )
{
   for( unsigned int i = 0; i < p_paths.size(); i++ )
   {
      p_paths[i].setID( i );

      if( setFilename )
      {
         char tmp[50];
         sprintf( tmp, "%03i", i );
         string incstr( tmp );
         string vtkfile = incstr + ".vtk";
         p_paths[i].setVTKFilename( vtkfile );
      }
   }
}

bool ListOfPaths::readXMLPaths( const char* filename )
{
   TiXmlDocument doc( filename );
   if( !doc.LoadFile() )
   {
      cout << "error - cannot open " << filename << endl ;
      return false;
   }

   TiXmlHandle hDoc(&doc);
   TiXmlElement* pElem;
   TiXmlHandle hRoot(0);

   {
      pElem = hDoc.FirstChildElement().Element();
      // cout << pElem->Value() << endl ;
      int num = 0;
      pElem->QueryIntAttribute("num", &num);
      // cout << "reading num paths: " << num << endl ;

      hRoot = TiXmlHandle( pElem );
   }


   //TiXmlElement* pathNode = hRoot.FirstChild( "Path" ).Child(i).Element();
   TiXmlElement* pathNode = hRoot.FirstChild( "Path" ).Element();
   for( ; pathNode; pathNode = pathNode->NextSiblingElement() )
   {
      Path P;
      string vtk_filename;
      int id;
      pathNode->QueryStringAttribute("filename", &vtk_filename );
      pathNode->QueryIntAttribute("id", &id );
      P.setVTKFilename( vtk_filename );
      P.setID( id );

      P.readXMLPath( pathNode );

      p_paths.push_back( P );

      //P.print();
      //cout << "----" << endl ;
   }

   return true;

}

void ListOfPaths::writeXMLPaths( const char* filename )
{
   cout << "writing paths to " << filename << endl ;
   TiXmlDocument doc;
   //TiXmlElement* msg;
   TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "", "" );  
   doc.LinkEndChild( decl );  

   TiXmlElement * root = new TiXmlElement( "AllPaths" );  
   root->SetAttribute("num", p_paths.size() );
   doc.LinkEndChild( root );  

   TiXmlComment * comment = new TiXmlComment();
   comment->SetValue( "List of Paths for a particular dataset" );  
   root->LinkEndChild( comment );  

   for( unsigned int i = 0; i < p_paths.size(); i++ )
   {
      TiXmlElement * pathTag = new TiXmlElement( "Path" );  
      string vtkfilename;

      if( p_paths[i].getVTKFilenames().size() > 0 )
         vtkfilename = p_paths[i].getVTKFilenames()[0].c_str();

      //cout << "filename test: " << vtkfilename << endl ;
      //cout << "size test: " << p_paths[i].getVTKFilenames().size() << endl;
      //p_paths[i].print();
      pathTag->SetAttribute( "filename", vtkfilename );
      pathTag->SetAttribute( "id", p_paths[i].getID() );

      root->LinkEndChild( pathTag );  


      p_paths[i].writeXMLPath( pathTag );

      //TiXmlElement * cxn = new TiXmlElement( "Connection" );  
      //root->LinkEndChild( cxn );  
      //cxn->SetAttribute("ip", "192.168.0.1");
      //cxn->SetDoubleAttribute("timeout", 123.456); // floating point attrib

      //dump_to_stdout( &doc );
   }

   doc.SaveFile( filename );
}

void ListOfPaths::print( const char* filename )
{
   cout << "writing paths to " << filename << endl ;
   ofstream fp_out;
   fp_out.open( filename );
   fp_out <<  "#slice label cost accumulated_cost\n" ;
   for( unsigned int i = 0; i < p_paths.size(); i++ )
      p_paths[i].print( fp_out );
   fp_out.close();

}


